import { Container } from "pixi.js";
import { ImageManager } from "@/managers/ImageManager.js";
import { SpritePool } from "@/utils/SpritePool.js";
import { blendmodes } from "@/const/blendmodes.js";
import { AudioManager } from "@/managers/AudioManager.js";
import { ScreenFilter } from "@/filters/ScreenFilter.js";
export class AnimatedContainer extends Container {
    constructor() {
        super();
        this.target=null;
        this.flashColor=[0,0,0,0];
        this.flashDuration=0;

        this.hidingDuration=0;


        this.source1 = null;
        this.source2 = null;
        this.cellsprites = [];
        this.rate = 4;
        this.duration = 0;
        
        this.delay = 0;
        this.animation = null;
        this.animTaskCount = 0;
        this.mirror = false;
        this.zIndex = 8;

        this.screenFilter=null;
        this.screenFlashDuration=0;
    }
    destroy(opts) {
        this.releaseCellSprites();
        if (this.source1) {
            ImageManager.releaseAnimation(this.source1.key);
        }
        if (this.source2) {
            ImageManager.releaseAnimation(this.source2.key);
        }
        super.destroy(opts);
    }

    remove() {
        if (this.parent && this.parent.removeChild(this)) {
            this.target.setBlendColor([0, 0, 0, 0]);
            this.target.show();
        }
        this.destroy({children:true});
    }

    releaseCellSprites() {
        for (let sprite of this.cellsprites) {
            this.removeChild(sprite);
            sprite.source = null;
            SpritePool.releaseSprite(sprite);
        }
    }

    setupDuration() {
        this.rate = 4;
        this.duration = this.animation.frames.length * this.rate + 1;
    }

    setup(target, animation, mirror, delay) {
        this.target=target;

        this.animation = animation;
        this.mirror = mirror;
        this.delay = delay;

        this.setupDuration();

        let anim1 = animation.animation1Name;
        if (anim1) {
            ++this.animTaskCount;
            ImageManager.loadAnimation(anim1).then(source => {
                this.source1 = source;
                --this.animTaskCount;
            });
        }
        let anim2 = animation.animation2Name;
        if (anim2) {
            ++this.animTaskCount;
            ImageManager.loadAnimation(anim2).then(source => {
                --this.animTaskCount;
                this.source2 = source;
            });
        }
        this.visible=true;
    }

    update() {
        if (this.isPlaying() && this.isReady()) {
            if (this.delay > 0) {
                --this.delay;
            } else {
                this.updateFrame();
                this.updateFlash();
                this.updateScreenFlash();
                this.updateHiding();
                --this.duration;
                if(!this.duration){
                    this.visible=false;
                }
            }
        }
    }
    startScreenFlash(color, duration) {
        this.screenFlashDuration = duration;
        if (!this.screenFilter) {
            this.screenFilter=new ScreenFilter();
            this.filters=[this.screenFilter];
        }else{
            this.screenFilter.enabled=true;
        }

        this.screenFilter.setTone(...color);
    }
    updateScreenFlash() {
        if (this.screenFlashDuration > 0) {
            let d = this.screenFlashDuration--;
            if (this.screenFilter) {
                this.screenFilter.opacity*=(d-1)/d;
                if(this.screenFlashDuration<=0){
                    this.screenFilter.enabled=false;
                }
            }
        }
    }

    startFlash(color, duration) {
        this.flashColor = [...color];
        this.flashDuration = duration;
    }
    updateFlash() {
        if (this.flashDuration > 0) {
            let d = this.flashDuration--;
            this.flashColor[3] *= (d - 1) / d;
            this.target.setBlendColor(this.flashColor);
        }
    }

    updateFrame() {
        this.updatePosition();
        if (this.duration % this.rate == 0) {
            let frameIndex = this.animation.frames.length - this.duration / this.rate;
            this.updateAllCellSprites(this.animation.frames[frameIndex]);

            for (let timing of this.animation.timings) {
                if (timing.frame == frameIndex) {
                    this.processTimingData(timing);
                }
            }
        }
    }

    updatePosition() {
        if (this.animation.position == 3) {
            this.x = this.parent.width / 2;
            this.y = this.parent.height / 2;
        } else {
            if(!this.target)return;
            let parent = this.target.parent;
            let grandparent = parent ? parent.parent : null;
            this.x = this.target.x;
            this.y = this.target.y;
            if (this.parent == grandparent) {
                this.x += parent.x;
                this.y += parent.y;
            }
            if (this.animation.position == 0) {
                this.y -= this.target.height;
            } else if (this.animation.position == 1) {
                this.y -= this.target.height / 2;
            }
        }
    }


    startHiding(duration) {
        this.hidingDuration = duration;
        this.target.hide();
    }

    updateHiding(){
        if (this.hidingDuration > 0) {
            --this.hidingDuration;
            if (this.hidingDuration === 0) {
                this.target.show();
            }
        }
    }

    processTimingData(timing) {
        let duration = timing.flashDuration * this.rate;
        switch (timing.flashScope) {
            case 1:
                this.startFlash(timing.flashColor, duration);
                break;
            case 2:
                this.startScreenFlash(timing.flashColor, duration);
                break;
            case 3:
                this.startHiding(duration);
                break;
        }
        if (timing.se) {
            AudioManager.playSe(timing.se);
        }
    }
    

    

    updateAllCellSprites(frame) {
        let frameLen = frame.length;
        for (let i = 0; i < frameLen; ++i) {
            let sprite = this.cellsprites[i];
            if (!sprite) {
                sprite = SpritePool.newSprite();
                this.cellsprites.push(sprite);
                this.addChild(sprite);
            }
            this.updateCellSprite(sprite, frame[i]);
        }

        let cellLength = this.cellsprites.length;
        for (let start = frameLen; start < cellLength; ++start) {
            let sprite = this.cellsprites[start];
            this.removeChild(sprite);
            sprite.source = null;
            SpritePool.releaseSprite(sprite);
        }
        this.cellsprites.length = frameLen;
    }

    updateCellSprite(sprite, cell) {
        let pattern = cell[0];
        if (pattern >= 0) {
            let sx = pattern % 5 * 192;
            let sy = Math.floor(pattern % 100 / 5) * 192;
            let mirror = this.mirror;
            let source = pattern < 100 ? this.source1 : this.source2;
            if (source?.refCount != undefined) {
                ++source.refCount;
            }
            sprite.source = source;
            sprite.setFrame(sx, sy, 192, 192);
            
            sprite.x = cell[1];
            sprite.y = cell[2];
            sprite.rotation = cell[4] * Math.PI / 180;
            sprite.scale.x = cell[3] / 100;

            if (cell[5]) {
                sprite.scale.x *= -1;
            }
            if (mirror) {
                sprite.x *= -1;
                sprite.rotation *= -1;
                sprite.scale.x *= -1;
            }

            sprite.scale.y = cell[3] / 100;
            sprite.alpha = cell[6] / 255;
            sprite.blendMode = blendmodes[cell[7]];
            sprite.visible = true;
        } else {
            sprite.visible = false;
        }
    }

    isPlaying() {
        return this.duration > 0;
    }
    isReady() {
        return this.animTaskCount <= 0;
    }
}